//////////////////////////////////////////////////////////////////////////////////
//
// ActionScript 3.0 Common Code Library (MIT License)
// Copyright (c) 2009 AS3CommonCode | Tony Birleffi | http://www.mosaiceye.com
// 
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////////

package org.as3commoncode.collections
{
	import org.as3commoncode.collections.IMap;
	import org.as3commoncode.collections.IList;
	import org.as3commoncode.collections.ArrayList;
	
	/**
	 * A simple map class.
	 * 
	 * @see	org.as3commoncode.collections.IMap;
	 * @author Tony Birleffi
	 */	
	public class SimpleMap implements IMap
	{
		/** * The keys list. */
		protected var keys:IList;
		
		/** * The vals list. */
		protected var vals:IList;
		
		/** * The by key object. */
		protected var byKey:Object;
		
		/** * The all keys are string boolean. */
		protected var allKeysAreStrings:Boolean;
		
		/**
		 * Constructor.
		 */
		public function SimpleMap() 
		{
			super();
			keys = new ArrayList();
			vals = new ArrayList();
			allKeysAreStrings = true;
		}
		
		/**
		 * Put an item in the map.
		 * 
		 * @param key	Object.
		 * @param val	Object.
		 */
		public function putItem(key:Object, val:Object):void
		{
			var n:Number = getIndexOfKey(key);
			if(n > -1){
				keys.setItemAt(n,key);
				vals.setItemAt(n,val);
			} else {
				keys.addItem(key);
				vals.addItem(val);
			}
			if(typeof(key) != "String") allKeysAreStrings = false;
			if(allKeysAreStrings) byKey[key] = val;
		}
		
		/**
		 * Get the keys from the map.
		 * 
		 * @return IList;
		 */
		public function getKeys():IList
		{
			return keys;
		}
		
		/**
		 * Get the vals from the map.
		 * 
		 * @return IList;
		 */
		public function getValues():IList
		{
			return vals;
		}
		
		/**
		 * Get the value from the object passed through.
		 * 
		 * @return Object.
		 */
		public function getValue(key:Object):Object
		{
			// try a quick lookup first
			if(allKeysAreStrings) return byKey[key];
			// then do the scanning lookup
			var idx:int = getIndexOfKey(key);
			if(idx == -1) return null;
			var o:Object = vals.getItemAt(idx);
			return o;
		}
		
		/**
		 * If the key exists in the map.
		 * 
		 * @return Boolean.
		 */
		public function keyExists(key:Object):Boolean
		{
			return getIndexOfKey(key) > -1;
		}
		
		/**
		 * If the value exists in the map.
		 * 
		 * @return Boolean.
		 */
		public function valueExists(val:Object):Boolean
		{
			return getIndexOfValue(val) > -1;
		}
		
		/**
		 * A string representation of the map.
		 * 
		 * @return String.
		 */
		public function toString():String
		{
			var str:String = "{";
			var i:Number;
			var s:Number;
			s = keys.size();
			for(i = 0; i < keys.size(); i++){
				if(i > 0) str += ", ";
				str+= keys.getItemAt(i) + ":" + vals.getItemAt(i);
			}
			str += "}";
			return str;
		}
		
		/**
		 * Get the index of a key in the map.
		 * 
		 * @return int.
		 */
		protected function getIndexOfKey(key:Object):int
		{
			return keys.indexOf(key);
		}
		
		/**
		 * Get the index of a value in the map.
		 * 
		 * @return int.
		 */
		protected function getIndexOfValue(val:Object):int
		{
			return vals.indexOf(val);
		}
	}
}